//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2004 Siemens AG
//
// Version: 1.1.2.5
// Date:    11. Jan. 2006
//////////////////////////////////////////////////////////////////////////////


#ifdef RIL_ENABLE_SIMTK

#ifdef SIEMENS_MAGNETO
#include "rilsimtk_magneto.cpp"
#else // SIEMENS_MAGNETO
#include "rilsimtk_ozone.cpp"
#endif // SIEMENS_MAGNETO

//////////////////////////////////////////////////////////////////////////////
//
// Functions for SAT handling without difference between Magneto and Ozone.
//
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
//
// Constructor
//
//////////////////////////////////////////////////////////////////////////////
CSimToolkitHandling::CSimToolkitHandling() {
  InitializeCriticalSection(&m_csLockBuffer);
  m_pRilDevice = 0;
  m_fNoResponse = FALSE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Destructor
//
//////////////////////////////////////////////////////////////////////////////
CSimToolkitHandling::~CSimToolkitHandling() {
  Deinit();
  DeleteCriticalSection(&m_csLockBuffer);
}

//////////////////////////////////////////////////////////////////////////////
//
// Initialize and start the SAT handling.
//
// Params:
//  pRilHandle: Pointer to the connected CRilHandle instance which is needed
//              internally.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::Init(CRilHandle* pRilDevice) {
  if (!pRilDevice) {
    return FALSE;
  }

  // Store the RIL device
  m_pRilDevice = pRilDevice;

  // Enable SAT handling
  if (!QueueInternalCmd(COMMAND_PORT, m_pRilDevice, "AT^SSTA=1,1\r", CMDOPT_NONE, APIID_FETCHSIMTOOLKITCMD, 0, 2, 10000)) {
    RILRetailTrace((TEXT("RilDrv: SimToolkit Error - Failed to queue SAT enable cmd -> SimToolkit NOT enabled !!!\r\n")));
    return FALSE;
  }

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Stop the SAT handling.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::Deinit(void) {
  // Nothing to do for now
  m_pRilDevice = 0;
  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Get the SAT profile.
//
// Params:
//  pHandle: Pointer to CRilInstanceHandle to be used for the operation.
//
// Return:
//  S_OK on successs, E_FAIL otherwise.
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CSimToolkitHandling::GetProfile(CRilInstanceHandle* pHandle) {
HRESULT hr;

  if (!QueueCmd(COMMAND_PORT, pHandle, "AT^SSTA?\r", CMDOPT_NONE, APIID_GETSIMTOOLKITPROFILE, ParseGetProfile, NULL, hr)) {
    return E_FAIL;
  }
  return S_OK;
}

//////////////////////////////////////////////////////////////////////////////
//
// Set the SAT profile.
//
// Params:
//  pHandle: Pointer to CRilInstanceHandle to be used for the operation.
//
// Return:
//  Currently only E_NOTIMPL because Siemens modules doesn't support setting
//  of SAT profile.
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CSimToolkitHandling::SetProfile(CRilInstanceHandle* pHandle) {
  return E_NOTIMPL;
}

//////////////////////////////////////////////////////////////////////////////
//
// Put a SAT command into the command queue.
//
// Params:
//  dwCmd: Number of SAT command.
//
// Return:
//  S_OK on successs, E_FAIL otherwise.
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CSimToolkitHandling::QueueSimToolkitCmd(DWORD dwCmd) {
char szCmd[32];

  sprintf(szCmd, "AT^SSTGI=%d\r", dwCmd);

  if (!QueueInternalCmd(COMMAND_PORT, m_pRilDevice, szCmd, CMDOPT_NONE, APIID_FETCHSIMTOOLKITCMD, 0, SIMTK_CMD_RETRIES, SIMTK_CMD_RETRY_DELAY, ParseGetCommand, NULL, this)) {
    RILRetailTrace((TEXT("RilDrv: SimToolkit Error - Failed to queue SAT cmd %d\r\n"), dwCmd));
    return E_FAIL;
  }

  return S_OK;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function called to parse a SAT notification.
//
// Params:
//  rszPointer: Pointer to the received SAT notification.
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseNotification(LPCSTR& rszPointer) {
LPCSTR  szDummy;
UINT    nValue;

  if (!ParseUInt(rszPointer, FALSE, nValue, rszPointer)) {
    RILRetailTrace((TEXT("RilDrv: ParseSIMToolkitNotification: failed to find value\r\n")));
    return FALSE;
  }

  // Look for the "<postfix>" (don't increase string pointer, postfix is scanned again in global response handler)
  if (!ParseRspPostfix(rszPointer, szDummy)) {
    RILRetailTrace((TEXT("RilDrv: ParseSIMToolkitNotification: failed to find postfix\r\n")));
    return FALSE;
  }

  if (nValue == 255) {
    // Full SIM reset, this corresponds to a SAT-Refresh with details 4
    void*  pBlob;
    UINT   cbBlob;
    return SUCCEEDED(ParseRefresh("4\r\n", pBlob, cbBlob));
  } else if ((nValue == 254) || ((nValue > 100) && (nValue < 200))) {
    return m_pRilDevice->BroadcastRealBlobNotification(RIL_NOTIFY_SIMTOOLKITSESSIONEND, NULL, 0);
  } else {
    return SUCCEEDED(QueueSimToolkitCmd(nValue));
  }

  return FALSE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing callback if something went wrong -> try to bring the module back
// into a proper state.
//
// Return:
//  S_OK on successs, E_FAIL otherwise.
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CSimToolkitHandling::ParseRspError(LPCSTR szRsp, LPVOID pParam) {
CSimToolkitHandling* pInstance = (CSimToolkitHandling*)pParam;

  RILRetailTrace((TEXT("RilDrv: SimToolkit: Response-Error\r\n")));

  if (!pInstance) {
    return E_FAIL;
  }

  if (!QueueInternalCmd(COMMAND_PORT, pInstance->m_pRilDevice, "AT^SSTR=254\r", CMDOPT_NONE, APIID_SENDSIMTOOLKITCMDRESPONSE, 0, SIMTK_CMD_RETRIES, SIMTK_CMD_RETRY_DELAY)) {
    RILRetailTrace((TEXT("RilDrv: SimToolkit Error - Failed to queue quit cmd\r\n")));
    return E_FAIL;
  }

  if (!pInstance->m_pRilDevice->BroadcastRealBlobNotification(RIL_NOTIFY_SIMTOOLKITSESSIONEND, NULL, 0)) {
    RILRetailTrace((TEXT("RilDrv: SimToolkit Error - Failed broadcast RIL_NOTIFY_SIMTOOLKITSESSIONEND\r\n")));
    return E_FAIL;
  }

  return S_OK;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing callback to parse the the SAT profile.
//
// Return:
//  S_OK on successs, E_FAIL otherwise.
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CSimToolkitHandling::ParseGetProfile(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam) {
UINT     i;
UINT     nValue;
UINT     cbProfileString;
LPSTR    szProfileString = NULL;
LPSTR    pchProfileStringWalk;
UINT     cbProfile;
BYTE*    pbProfileWalk;
BYTE*    pbProfile = NULL;
HRESULT  hr = S_OK;

  pBlob = NULL;
  cbBlob = 0;

  // Parse "<prefix>^SSTA: <state>,<alphabet>,<allowedInstance>,<Profile>"
  if (!ParseRspPrefix(szRsp, szRsp)                   ||
      !MatchStringBeginning(szRsp, "^SSTA: ", szRsp)  ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp)          ||
      !MatchStringBeginning(szRsp, ",", szRsp)        ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp)          ||
      !MatchStringBeginning(szRsp, ",", szRsp)        ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp)          ||
      !MatchStringBeginning(szRsp, ",", szRsp)) {
    hr = E_FAIL;
    goto Error;
  }

  // Parse "<profile>"
  // NOTE: we take ownerswhip of allocated szProfileString
  if (!ParseUnlimitedString(szRsp, szProfileString, cbProfileString, szRsp)) {
    hr = E_FAIL;
    goto Error;
  }
  TBD_ASSERT(0 == (cbProfileString - 1) % 2);
  cbProfile = (cbProfileString - 1) / 2;

  // Allocate the byte array of needed size
  pbProfile = (BYTE*)AllocBlob(cbProfile);
  if (!pbProfile) {
    hr = E_OUTOFMEMORY;
    goto Error;
  }

  // Decode the profile
  pbProfileWalk = pbProfile;
  pchProfileStringWalk = szProfileString;
  for (i = 0; i < cbProfile; i++) {
    *pbProfileWalk = SemiByteCharsToByte(*pchProfileStringWalk, *(pchProfileStringWalk + 1));
    pbProfileWalk++;
    pchProfileStringWalk += 2;
  }

  // Parse "<postfix>"
  if (!ParseRspPostfix(szRsp, szRsp)) {
    hr = E_FAIL;
    goto Error;
  }

  pBlob = (void*)pbProfile;
  cbBlob = cbProfile;

Error:
  if (FAILED(hr)) {
    FreeBlob(pbProfile);
  }
  delete[] szProfileString;
  return hr;
}

//////////////////////////////////////////////////////////////////////////////
//
// Trace the binary data of the SIMToolkit blob passed tt the MMI.
//
// Params:
//  pBlob : Pointer to the blob
//  dwSize: Size of the blob
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
void CSimToolkitHandling::TraceBlob(BYTE* pBlob, DWORD dwSize) {
#ifdef SIMTK_ENABLE_BIN_TRACE
  RILRetailTrace((TEXT("RilDrv: -----------------------------------------------------------------------\r\n")));
  RILRetailTrace((TEXT("RilDrv: SIM-Toolkit blob data (size: %d)\r\n"), dwSize));
  TCHAR   Buf[1024];
  TCHAR*  pBuf = Buf;
  BOOL    tr = FALSE;
  for (DWORD i = 1; i <= dwSize; i++) {
    _stprintf(pBuf, TEXT("0x%02X "), pBlob[i-1]);
    pBuf += 5;
    if (i && !(i % 16)) {
      swprintf(pBuf, TEXT("\r\n"));
      RILRetailTrace((Buf));
      pBuf = Buf;
      tr = TRUE;
    } else {
      tr = FALSE;
    }
  }
  if (!tr) {
    _stprintf(pBuf, TEXT("\r\n"));
    RILRetailTrace((Buf));
  }
  RILRetailTrace((TEXT("RilDrv: -----------------------------------------------------------------------\r\n")));
#endif // SIMTK_ENABLE_BIN_TRACE
}

#endif // RIL_ENABLE_SIMTK

